package com.awesumgames.awesum;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import android.opengl.GLES20;

import com.awesumgames.awesum.AwesumGlobal.Awesum;
import com.awesumgames.awesum.AwesumGlobal.Awesum.Load;

public final class Shader {
	public int program = -1;
	public Map<String, Arg> uniforms = new HashMap<String, Arg>();
	public Map<String, Arg> attributes = new HashMap<String, Arg>();
	private ArrayList<Integer> handles = new ArrayList<Integer>();
	public enum ArgType { UserDefined, MVP, MV, Color, Texture, TexCoord, Pos, Normal, Light; }
	public int color=0;
	public int texture=0;
	public int mvp=0;
	public int mv=0;
	public int pos=0;
	public int texCoord=0;
	public int normal=0;
	public int light=0;
	
	public final void compile(int shader, int type) throws IOException {
		int s = GLES20.glCreateShader(type);
		if (s != 0) {
			GLES20.glShaderSource(s, Load.File(shader));
			GLES20.glCompileShader(s);

			final int[] compileStatus = new int[1];
			GLES20.glGetShaderiv(s, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
			
	        if (compileStatus[0] == 0) { //compilation failed?
				GLES20.glDeleteShader(s);
				s = 0;
	        }
		}
		if (s == 0)
			throw new RuntimeException("Error creating shader " + shader + " type " + type);
		handles.add(s);
	}
	
	public void link() {
		program = GLES20.glCreateProgram();
		
		if (program != 0) {
			for (Integer i : handles)
				GLES20.glAttachShader(program, i.intValue());
			
			//GLES20.glBindAttribLocation(programHandle, 0, "a_pos");
			//GLES20.glBindAttribLocation(programHandle, 1, "a_color");
			
			GLES20.glLinkProgram(program);
			
			final int[] linkStatus = new int[1];
			GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
			
			if (linkStatus[0] == 0) { //link failed                     
				GLES20.glDeleteProgram(program);
				program = 0;
			}
		}
		
		if (program == 0)
			throw new RuntimeException("Error creating GLES20 program.");
	}
	
	public final void addU(String name, ArgType type) {
		int u = GLES20.glGetUniformLocation(program, name);
		uniforms.put(name, new Arg(name, u, type));
		assign(type, u);
	}
	public final void addA(String name, ArgType type) {
		int a = GLES20.glGetAttribLocation(program, name);
		attributes.put(name, new Arg(name, a, type));
		GLES20.glEnableVertexAttribArray(a);
		assign(type, a);
	}
	private void assign(ArgType t, int handle) {
		switch (t) {
			case MVP: mvp = handle; break;
			case MV: mv = handle; break;
			case Pos: pos = handle; break;
			case Color: color = handle; break;
			case Normal: normal = handle; break;
			case Texture: texture = handle; break;
			case TexCoord: texCoord = handle; break;
			case Light: light = handle; break;
		}
	}
	
	public final void use() {
		GLES20.glUseProgram(program);
		Game.Shaders.current = this;
	}
	
	public class Arg {
		public ArgType type = ArgType.UserDefined;
		public String name;
		public int handle;
		public Arg(String argname, int arghandle, ArgType argtype) {
			name = argname;
			handle = arghandle;
			type = argtype;
		}
	}
}
